package com.caijinbang.study.utils.access;

import com.google.common.base.Stopwatch;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.Collection;
import java.util.List;

/**
 * mongodb查询入口
 *
 * @author caijb
 * @version 1.0.0
 * @date 2018-05-03 13:03
 */
@Slf4j
public class MongoAccess {

    private MongoTemplate mongoTemplate;

    /**
     * 根据id查询实体
     *
     * @param id          id
     * @param entityClass 实体类
     * @param <T>
     * @return
     */
    public <T> T get(Object id, Class<T> entityClass) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            return mongoTemplate.findById(id, entityClass);
        } finally {
            log.info("get, id={},  entityClass={}, elapsedTime={}", id, entityClass.getName(), stopwatch.stop());
        }
    }

    /**
     * 根据条件查询实体
     *
     * @param query
     * @param entityClass
     * @param <T>
     * @return
     */
    public <T> List<T> find(Query query, Class<T> entityClass) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            return mongoTemplate.find(query, entityClass);
        } finally {
            log.info("find by Query, query={}, entityClass={}, elapsedTime={}", query, entityClass.getName(), stopwatch.stop());
        }
    }

    /**
     * 查询所有实体
     *
     * @param entityClass
     * @param <T>
     * @return
     */
    public <T> List<T> findAll(Class<T> entityClass) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            return mongoTemplate.findAll(entityClass);
        } finally {
            log.info("findAll, entityClass={}, elapsedTime={}", entityClass.getName(), stopwatch.stop());
        }
    }

    /**
     * 返回一个文档满足指定的查询条件。如果多个文档满足查询,该方法返回第一个文档,如果没有文档满足查询,方法返回null
     *
     * @param query       查询条件
     * @param entityClass 实体类
     * @param <T>
     * @return
     */
    public <T> T findOne(Query query, Class<T> entityClass) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            return mongoTemplate.findOne(query, entityClass);
        } finally {
            log.info("findOne by Query, query={}, entityClass={}, elapsedTime={}", query, entityClass, stopwatch.stop());
        }
    }

    /**
     * 保存实体,若新增的数据中存在主键,则更改原来的内容为新内容
     *
     * @param entity
     */
    public void save(Object entity) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            mongoTemplate.save(entity);
        } finally {
            log.info("save, entityClass={}, elapsedTime={}", entity.getClass().getName(), stopwatch.stop());
        }
    }

    /**
     * 批量插入实体,若新增的数据中存在主键insert() 会提示错误
     *
     * @param entities
     * @param entityClass
     */
    public void batchInsert(Collection<? extends Object> entities, Class<?> entityClass) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            mongoTemplate.insert(entities, entityClass);
        } finally {
            log.info("batchInsert, size={}, entityClass={}, elapsedTime={}", entities.size(), entityClass.getName(), stopwatch.stop());
        }
    }

    /**
     * 批量新增
     *
     * @param entities
     */
    public void batchInsertAll(Collection<? extends Object> entities) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            mongoTemplate.insertAll(entities);
        } finally {
            log.info("insertAll, size={}, elapsedTime={}", entities.size(), stopwatch.stop());
        }
    }

    /**
     * 修改符合条件第一条记录
     *
     * @param query
     * @param update
     * @param entityClass
     * @return
     */
    public UpdateResult updateFirst(Query query, Update update, Class entityClass) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            return mongoTemplate.updateFirst(query, update, entityClass);
        } finally {
            log.info("updateFirst,query={}, update={}, entityClass={}, elapsedTime={}", query, update, entityClass.getName(), stopwatch.stop());
        }
    }

    /**
     * 修改符合条件的所有
     *
     * @param query
     * @param update
     * @param entityClass
     * @return
     */
    public UpdateResult updateMulti(Query query, Update update, Class<?> entityClass) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            return mongoTemplate.updateMulti(query, update, entityClass);
        } finally {
            log.info("updateMulti,query={}, update={}, entityClass={}, elapsedTime={}", query, update, entityClass.getName(), stopwatch.stop());
        }
    }

    /**
     * 修改符合条件时如果不存在则添加
     *
     * @param query
     * @param update
     * @param entityClass
     * @return
     */
    public UpdateResult upsert(Query query, Update update, Class<?> entityClass) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            return mongoTemplate.upsert(query, update, entityClass);
        } finally {
            log.info("upsert,query={}, update={}, entityClass={}, elapsedTime={}", query, update, entityClass.getName(), stopwatch.stop());
        }
    }

    /**
     * 删除实体
     *
     * @param entity
     */
    public void delete(Object entity) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            mongoTemplate.remove(entity);
        } finally {
            log.info("delete, entityClass={}, elapsedTime={}", entity.getClass().getName(), stopwatch.stop());
        }
    }

    /**
     * 根据条件删除
     *
     * @param query       查询条件
     * @param entityClass 实体
     * @return
     */
    public DeleteResult delete(Query query, Class<?> entityClass) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            return mongoTemplate.remove(query, entityClass);
        } finally {
            log.info("delete, query={}, entityClass={}, elapsedTime={}", query, entityClass.getName(), stopwatch.stop());
        }
    }

    /**
     * 批量删除(根据id集合)
     *
     * @param ids         id集合
     * @param entityClass 实体
     * @param <T>
     */
    public <T> void batchDelete(List<Integer> ids, Class<T> entityClass) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        Query query = Query.query(Criteria.where("id").in(ids));
        try {
            mongoTemplate.findAllAndRemove(query, entityClass);
        } finally {
            log.info("batch delete,query={}, entityClass={}, elapsedTime={}", query, entityClass.getName(), stopwatch.stop());
        }
    }

    /**
     * 根据条件统计
     *
     * @param query       查询条件
     * @param entityClass 实体
     * @return
     */
    public long count(Query query, Class<?> entityClass) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            return mongoTemplate.count(query, entityClass);
        } finally {
            log.info("count, query={}, entityClass={}, elapsedTime={}", query, entityClass.getName(), stopwatch.stop());
        }
    }

    /**
     * 聚合查询
     *
     * @param aggregation
     * @param inputTypeClass
     * @param outputTypeClass
     * @param <O>
     * @return
     */
    public <O> AggregationResults<O> aggregate(Aggregation aggregation, Class<?> inputTypeClass, Class<O> outputTypeClass) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            return mongoTemplate.aggregate(aggregation, inputTypeClass, outputTypeClass);
        } finally {
            log.info("aggregate, aggregation={}, inputTypeClass={}, outputType={}, elapsedTime={}", aggregation, inputTypeClass, outputTypeClass.getName(), stopwatch.stop());
        }
    }

    
    public void setMongoTemplate(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

}
